#include <string.h>
//#include <time.h>

struct amx_info_t
{
	AMX *file;
	int onplayercmd_idx;
};

typedef std::list<amx_info_t> amx_list_t;

static amx_list_t amx_list;


// funcs


int exec_onplayercommandtext(int playerid, const char *cmdtext)
{
	//AMX *amx;
	cell
		amx_addr = 0,
		amx_ret = 0,
		*amx_physAddr;

	if(amx_list.empty()) return 0;
	for(amx_list_t::iterator it = amx_list.begin(), en = amx_list.end(); it != en; ++it)
	{
		if(it->onplayercmd_idx != -1)
		{
			//amx = it->file;
			amx_PushString(it->file, &amx_addr, &amx_physAddr, cmdtext, 0, 0);
			amx_Push(it->file, (cell) playerid);

			//logprintf("amx_ret1: %d, &amx_ret: %p",amx_ret, &amx_ret);
			amx_Exec(it->file, (cell*)&amx_ret, it->onplayercmd_idx);
			//logprintf("amx_ret2: %d, &amx_ret: %p",amx_ret, &amx_ret);
			amx_Release(it->file, amx_addr);

			if(amx_ret) 
				return amx_ret;
			amx_addr = 0;
		}
	}
	return 0;

}

/*
NATIVE_DECL(mystrlen) ( AMX* amx, cell* params )
{
	char *str;
	amx_StrParam(amx, params[1], str);
	if(str == NULL) return 0;
	unsigned short i=0;
	while(*(str++)!='\0') i++;
	return i;
}
#define myislower(a) ((a)>='a'&&(a)<='z')
#define mytoupper(a) (myislower(a)?(a-0x20):(a))
//#define myisupper(a) ((a)>='A'&&(a)<='Z')
//#define mytolower(a) (myisupper(a)?(a+0x20):(a))
#define mymax(a,b) ((a)>(b)?(a):(b))

inline unsigned short mystrlen(char *str)
{
	unsigned short i=0;
	while(*str++) i++;
	return i;
}

inline char mytolower(char a)
{
	return((a>='A'&&a<='Z')?(a+0x20):a);
}

NATIVE_DECL(mystrcmp) ( AMX* amx, cell* params )
{
	char *str1,*str2;
//	unsigned short i;//,len;
	amx_StrParam(amx, params[1], str1);
	amx_StrParam(amx, params[2], str2);
	//if(str1 == NULL) return(str2 == NULL);
	//else if(str2 == NULL) return(false);
	if(str1 == NULL || str2 == NULL) return(str2 == str1);
	while(true)
		if(!(*str1)) return(!(*str2));
		else if(!(*str2)) return(false);
		else if(mytolower(*(str1++))!=mytolower(*(str2++))) return false;
	return true;
}


NATIVE_DECL(mystrcmp2) ( AMX* amx, cell* params )
{
	char *str1,*str2;
	unsigned short i, len1, len2;

	amx_StrParam(amx, params[1], str1);
	amx_StrParam(amx, params[2], str2);

	if(str1 == NULL || str2 == NULL) return(str2 == str1);


	len1 = strlen(str1);
	len2 = strlen(str2);

	if(len1 != len2) return false;

	for(i = 0; i < len1; i++)
		if(mytolower(*(str1++))!=mytolower(*(str2++))) return false;
	return true;
}
*/

NATIVE_DECL(stricmp) ( AMX* amx, cell* params )
{
	cell *c1, *c2;
	int l1, l2;
	//amx_StrParam(amx, params[1], str1);
	//amx_StrParam(amx, params[2], str2);
	amx_GetAddr(amx, params[1], &c1);
	amx_GetAddr(amx, params[2], &c2);
	amx_StrLen(c1, &l1);
	amx_StrLen(c2, &l2);
	
	if(l1 != l2) return 0;
	
	if(!c1 || !c1) return(c2 == c1);
	
	//return (str1[0] != str2[0]) ? 0 : (strnicmp(str1, str2, l1));
	while (*c1)
	{
		char ch1 = *c1, ch2 = *c2;
		if(('a' <= ch1 && ch1 <= 'z') || ('a' <= ch2 && ch2 <= 'z'))
		{
			ch1 &= ~0x20;
			ch2 &= ~0x20;
		}
		if(ch1 != ch2) return false;

		c1++, c2++;
	}
	return (true);
}

/*
NATIVE_DECL(mystrstart) ( AMX* amx, cell* params )
{
	char *str1,*str2;
	unsigned short i;//,len;
	amx_StrParam(amx, params[1], str1);
	amx_StrParam(amx, params[2], str2);
	if(str1 == NULL || str2 == NULL) return(str2 == str1);
	for(i = 0; true; i++)
		if(!str1[i]) return(!str2[i]);
		else if(!str2[i]) return(true);
		else if(str1[i] != str2[i]) return false;
	return true;
}
*/

NATIVE_DECL(scrash) ( AMX* amx, cell* params )
{
	/*
	int *crasher = NULL;
	return(*crasher);
	*/
	exit(2);
	return 1;
}




NATIVE_DECL(strend) ( AMX* amx, cell* params )
{
	char *str;//, *src;
	int idx;
	cell *dest;
	amx_StrParam(amx, params[2], str);
	if(str == NULL) return 0;
	//logprintf("str: %s", str);
	idx = (int) (params[3]);
	//logprintf("idx: %d", idx);
	if(idx > strlen(str)) idx = strlen(str);
	//logprintf("idx2: %d", idx);
	while(str[idx] <= ' ' && str[idx] > '\0') idx++;
	//logprintf("idx3: %d", idx);
	amx_GetAddr(amx, params[1], &dest);
	amx_SetString(dest, (str+idx), 0, 0, params[4]);
	return 1;
}
//native mystrtok(src[], const str[], idx, delim, srcsize);
NATIVE_DECL(strtok) ( AMX* amx, cell* params )
{
  
	cell *str; 
	int delim;
	cell *index;
	cell *dsrc;
	{
		//amx_StrParam(amx, params[2], str);
		amx_GetAddr(amx, params[2], &str);
		if(!str) 
			return 0;
		delim = params[4];
		amx_GetAddr(amx, params[3], &index);
		
		amx_GetAddr(amx, params[1], &dsrc);
	}
	cell length,
		size = params[5] - 1;
		
	if(size < 1) 
		return 0;
	
	amx_StrLen(str, &length);
		
	if(length <= *index || *index < 0) 
	{
		*dsrc = '\0';
		return 0;
	}
	
	cell *str_t;
	str_t = str + *index; // &str[*index]
	
	while (*str_t && (*str_t <= ' '))
	{
		(*index) += 1;
		str_t++;
	}
	
	int offset = *index;
	//while ((*index < length) && (str[index] >= ' ')&& (str[index] != delim) && ((index - offset) < size))
	//	index++;
	
	//str_t = str + *index;
	
	
	int i = 0;
	while(*str_t && *str_t > ' ' && *str_t != delim && (*index - offset) < size)
	{
		*dsrc = *str_t;
		(*index) += 1;
		str_t++;
		dsrc++;
		
	}
	
	*dsrc = '\0';
	
	return 1;
}
// native mygetxy(&Float:x, &Float:y, Float:a, Float:dist);
NATIVE_DECL(getxy) ( AMX* amx, cell* params )
{
	cell *x_dest, *y_dest;
	amx_GetAddr(amx, params[1], &x_dest);
	amx_GetAddr(amx, params[2], &y_dest);
	float x = amx_ctof(*x_dest), y = amx_ctof(*y_dest);

	float ang = amx_ctof(params[3]), dist = amx_ctof(params[4]);
	ang = (-ang)*(PI/180);
	x+= (float) (dist * sin(ang));
	y+= (float) (dist * cos(ang));
	//logprintf("%f", (dist * sin((ang-90.0)*(180/PI))));
	*x_dest = amx_ftoc(x);
	*y_dest = amx_ftoc(y);
	return 1;
}


NATIVE_DECL(rand) ( AMX* amx, cell* params )
{
	return (cell)(rand());
}

// native mysendplayercmd(playerid, cmdtext[]);
NATIVE_DECL(sendplayercmd) ( AMX* amx, cell* params )
{
	char *cmdtext;
	amx_StrParam(amx, params[2], cmdtext);
	//logprintf("playerid: %d, cmdtext: %s", playerid, cmdtext);

	int res = 0;
	if(cmdtext)
	{
		res = exec_onplayercommandtext(params[1], cmdtext);
		free(cmdtext);
	}
	return res;
}


/*
//mygetdist_cmp(x1, y1, z1, x2, y2, z2);
NATIVE_DECL(mygetdist_cmp) ( AMX* amx, cell* params )
{
#define x1 params[1]
#define x2 params[4]
#define y1 params[2]
#define y2 params[5]
#define z1 params[3]
#define z2 params[6]
#define sq(n) ((n)*(n))
	long int c1, c2;
	c1 = (sq(x1)+sq(y1)+sq(z1))/2;
	c2 = (sq(x2)+sq(y2)+sq(z2))/2;
	return (cell)(c1+c2-x1*x2-y1*y2-z1*z2);
}*/


NATIVE_DECL(command) ( AMX* amx, cell* params )
{
	char *cmd;
	amx_StrParam(amx, params[1], cmd);
	int res = 0;
	if(cmd) 
	{
		 res = system(cmd);
		 free(cmd);
	}
	return res;
}

NATIVE_DECL(getsyst) ( AMX* amx, cell* params )
{
	return
		(
#if defined WIN64
			2
#elif defined WIN32 //
			1
#elif defined LINUX
			3
#elif defined __MSDOS__
			4
#else
			0
#endif
		); // ;(
}

